package org.amphiprion.gameengine.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;

import org.amphiprion.diceroller.ApplicationConstants;
import org.amphiprion.diceroller.R;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.util.Log;

public class TextureHelper {
	private static HashMap<String, Texture> textures = new HashMap<String, Texture>();

	/**
	 * The first character of the URI must be the type of the URI <br>
	 * "D" for android drawable resource id (i.e. "R1236588") <br>
	 * "J" for java classpath resource name (i.e. "J/images/test.png") <br>
	 * "F" for a file path (i.e. "F/mnt/sdcard0/test.png")
	 * 
	 * @param context
	 * @param uri
	 * @return
	 */
	public static Texture loadTexture(final Context context, String uri) {
		char code = uri.charAt(0);
		if (code == 'J') {
			return loadTextureJavaResource(context, uri.substring(1));
		} else if (code == 'F') {
			return loadTextureFromFile(context, new File(uri.substring(1)));
		} else if (code == 'D') {
			return loadTextureFromAndroidResource(context, Integer.parseInt(uri.substring(1)));
		}
		throw new RuntimeException("Texture uri type unknown: " + code);
	}

	public static Texture loadTextureFromAndroidResource(final Context context, final int resourceId) {
		String key = "@R." + resourceId;
		Texture texture = textures.get(key);
		if (texture == null) {
			final BitmapFactory.Options options = new BitmapFactory.Options();
			options.inScaled = false; // No pre-scaling

			// Read in the resource
			final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
			texture = loadTexture(bitmap);
			textures.put(key, texture);
		}

		return texture;
	}

	public static Texture loadTextureJavaResource(Context context, String path) {
		// TODO: Marche pas (texture noire)
		Log.d(ApplicationConstants.PACKAGE, "*************Marche pas (texture noire)");
		String key = "@JAVA." + path;
		Texture texture = textures.get(key);
		if (texture == null) {
			try {
				InputStream is = TextureHelper.class.getResourceAsStream(path);
				if (is == null) {
					Bitmap bitmap = BitmapFactory.decodeStream(is);
					texture = loadTexture(bitmap);
					textures.put(key, texture);
				} else {
					return loadTextureFromAndroidResource(context, R.drawable.no_image);

				}
			} catch (Exception e) {
				return loadTextureFromAndroidResource(context, R.drawable.no_image);
			}

		}

		return texture;
	}

	public static Texture loadTextureFromFile(Context context, File file) {
		String key = file.toURI().toString();
		Texture texture = textures.get(key);
		if (texture == null) {
			try {
				if (file.exists()) {
					InputStream is = new FileInputStream(file);
					Bitmap bitmap = BitmapFactory.decodeStream(is);
					texture = loadTexture(bitmap);
					textures.put(key, texture);
				} else {
					return loadTextureFromAndroidResource(context, R.drawable.no_image);

				}
			} catch (Exception e) {
				return loadTextureFromAndroidResource(context, R.drawable.no_image);
			}

		}

		return texture;
	}

	private static Texture loadTexture(Bitmap bitmap) {
		Texture texture = new Texture();

		int originalWidth = bitmap.getWidth();
		int originalHeight = bitmap.getHeight();

		int mStrikeWidth = 1;
		while (mStrikeWidth < originalWidth) {
			mStrikeWidth <<= 1;
		}

		int mStrikeHeight = 1;
		while (mStrikeHeight < originalHeight) {
			mStrikeHeight <<= 1;
		}
		texture.height = mStrikeHeight;
		texture.width = mStrikeWidth;
		texture.originalHeight = originalHeight;
		texture.originalWidth = originalWidth;

		if (originalWidth != mStrikeWidth || originalHeight != mStrikeHeight) {
			Bitmap.Config config = Bitmap.Config.ARGB_4444;
			final Bitmap mBitmap = Bitmap.createBitmap(mStrikeWidth, mStrikeHeight, config);
			Canvas mCanvas = new Canvas(mBitmap);

			// if (angle != 0) {
			// Matrix orig = mCanvas.getMatrix();
			// orig.postTranslate(-bitmap.getWidth() / 2, -bitmap.getHeight() / 2);
			// orig.postRotate(angle, 0, 0);
			// orig.postTranslate(contentWidth / 2, contentHeight / 2);
			// mCanvas.setMatrix(orig);
			// }
			mCanvas.drawBitmap(bitmap, 0, 0, new Paint());
			mCanvas = null;
			loadGLTexture(mBitmap, texture);
			bitmap.recycle();
			// mBitmap = null;
		} else {
			loadGLTexture(bitmap, texture);
		}
		return texture;
	}

	private static void loadGLTexture(Bitmap bitmap, Texture texture) {
		final int[] textureHandle = new int[1];

		GLES20.glGenTextures(1, textureHandle, 0);
		if (textureHandle[0] != 0) {
			// Bind to the texture in OpenGL
			GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);

			// Set filtering
			GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
			GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);

			// Load the bitmap into the bound texture.
			GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);

			// Recycle the bitmap, since its data has been loaded into OpenGL.
			bitmap.recycle();
			texture.loaded = true;
			texture.textureId = textureHandle[0];
		}
		if (textureHandle[0] == 0) {
			throw new RuntimeException("Error loading texture.");
		}
	}

	public static void unloadAll() {
		int[] indexs = new int[1];
		for (Texture t : textures.values()) {
			indexs[0] = t.textureId;
			t.loaded = false;
			GLES20.glDeleteTextures(1, indexs, 0);
		}

		textures.clear();
	}
}